package com.mcy.springbatch.job;

import com.mcy.springbatch.entity.SysUser;
import com.mcy.springbatch.writer.SysUserItemWriter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 基本概念：
 * JobRepository：batch的持久化组件，job、step各种运行状以及参数态均通过JobRepository进行持久化
 * JobLauncher：任务启动器，用于启动任务
 * Job：代表一个具体的任务
 * Step：代表一个具体的步骤，一个Job可以包含一个或多个Step，Step的实现可以分为两种方式：tasklet和chunk，Step的chunk方式可以细化为读取数据ItemReader/处理数据ItemProcesser/写出数据ItemWriter。
 *
 * 核心API：
 * JobInstanc：Job每次执行都对应一个JobInstance，也就是一条数据，对应表BATCH_JOB_INSTANCE
 * JobExecution：标识JobInstance的一次运行，记录Job的运行状态信息等，JobInstance运行有成功或失败，所以一个JobInstance可以有多条JobExecution的记录，对应表BATCH_JOB_EXECUTION
 * JobParameters：Job的参数配置，不同的参数产生不同的JobInstance，一般用于区分Job运行，比如用日期来区分Job的每天运行
 * StepExecution：类似JobExecution，代表Step的一次运行
 * ExecutionContext：Job运行的上下文
 *
 * Flow：是多个Step的集合，Flow可以复用，即可以被多个Job复用，Flow是使用FlowBuilder创建
 * Split：并发Step执行
 * Decider：决策器
 * Job嵌套：JobStepBuilder实现
 * Listener：监听器
 */

@Slf4j
//@Configuration
public class BHelloworldJobConfig extends BaseJobConfig {

    private static final String jobName = "jobDemo";

    @Autowired
    private ListItemReader<SysUser> userDataListItemReader;

    @Autowired
    private SysUserItemWriter sysUserItemWriter;

    /**
     * 每个job可以有一个或多个step
     * @return
     */
    @Bean(name = jobName)
    public Job helloWorldJob() {
        return jobBuilderFactory.get(jobName)
                .start(jobDemoStep1())
                .next(jobDemoStep2())
                .next(jobDemoStep3())
                .build();

//                .start(splitDemoFlow1())
//                .split(new SimpleAsyncTaskExecutor())
//                .add(splitDemoFlow2())
//                .end()

//                .listener(null)
//                .incrementer(new RunIdIncrementer())

//                .start(jobDemoStep1())
//                .on("COMPLETED")
//                .to(jobDemoStep2())
//                .from(jobDemoStep2())
//                .on("FAILED")
//                .to(jobDemoStep3())
//                .from(jobDemoStep3())
//                .end()
//                .build();


    }

    /**
     * 使用tasklet方式创建step
     * 每个step只有一个tasklet
     * @return
     */
    @Bean
    public Step jobDemoStep1() {
        return stepBuilderFactory.get("jobDemoStep1")

                .<SysUser,SysUser>chunk(100)
                .reader(null)
                .processor(processor())
                .writer(null)

//                .tasklet((stepContribution, chunkContext) -> {
//                    log.info("---------------run jobDemoStep1,create by tasklet.");
//                    return RepeatStatus.FINISHED;
//                })
                .build();
    }

    /**
     * 使用chunk方式创建step
     * @return
     */
    @Bean
    public Step jobDemoStep2() {
        return stepBuilderFactory.get("jobDemoStep2")
                .<SysUser,SysUser>chunk(20)
                .faultTolerant()
                .skip(Exception.class)
                .skipLimit(10)
                .retry(Exception.class)
                .retryLimit(10)
                .reader(userDataListItemReader)
                .processor(processor())
                .writer(sysUserItemWriter)
                .build();
    }

    @Bean
    public Step jobDemoStep3() {
        return stepBuilderFactory.get("jobDemoStep3")
                .tasklet((stepContribution, chunkContext) -> {
                    log.info("---------------run jobDemoStep3,create by tasklet.");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }


    @Bean
    public ItemProcessor<SysUser,SysUser> processor(){
        return o -> {
            log.info("{},processing,do something",o);
            return o;
        };
    }

}